package org.pupil.rpc.spi;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * SPI机制
 */
public class ExtensionLoader {
    private Logger logger = LoggerFactory.getLogger(ExtensionLoader.class);

    // 系统SPI 前缀
    private static String SYS_EXTENSION_LOADER_DIR_PREFIX =  "META-INF/prpc/";

    // 用户SPI 前缀
    private static String DIY_EXTENSION_LOADER_DIR_PREFIX = "META-INF/rpc/";

    // 前缀集合
    private static String[] prefixs = {SYS_EXTENSION_LOADER_DIR_PREFIX, DIY_EXTENSION_LOADER_DIR_PREFIX};

    // bean定义信息 key: 定义的key value：具体类名
    private static Map<String, Class> extensionClassCache = new ConcurrentHashMap<>();

    // bean定义信息 key: 定义的key value：接口子类map集合
    private static Map<String, Map<String,Class>> extensionClassCaches = new ConcurrentHashMap<>();

    // 存储实例化的bean
    private static Map<String, Object> singletonsObject = new ConcurrentHashMap<>();

    /**
     * 通过静态加载，使得ExtensionLoader只创建一次
     * 每次调用都是同一个ExtensionLoader
     */
    private static ExtensionLoader extensionLoader;

    static {
        extensionLoader = new ExtensionLoader();
    }

    /**
     * 获取ExtensionLoader实例
     *
     * @return
     */
    public static ExtensionLoader getInstance() {
        return extensionLoader;
    }

    private ExtensionLoader() {

    }

    /**
     * 获取bean
     *
     * @param <V>
     * @return
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public <V> V get(String name) {
        // 当bean没有被实例化时，创建bean
        if (!singletonsObject.containsKey(name)) {
            try {
                // 实例化bean，进行本地缓存在singletonsObject
                singletonsObject.put(name, extensionClassCache.get(name).newInstance());
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
        }

        // 返回实例化bean
        return (V) singletonsObject.get(name);
    }

    /**
     * 获取接口所有子类
     *
     * @param clazz
     * @return
     */
    public List<Object> gets(Class clazz) {
        final String name = clazz.getName();

        // 如果extensionClassCaches没有clazz键值对，证明没有配置clazz，clazz非法
        if (!extensionClassCaches.containsKey(name)) {
            try {
                throw new ClassNotFoundException(clazz + "没有找到");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        }

        final Map<String, Class> classMap = extensionClassCaches.get(name);
        List<Object> classList = new ArrayList<>();
        if (classMap.size() > 0) {
            classMap.forEach((k, v) -> {
                // 如果bean已经被实例化，则直接从singletonsObject获取
                // 如果bean未被实例化，则创建实例存入singletonsObject并获取处理
                try {
                    classList.add(singletonsObject.getOrDefault(k, v.newInstance()));
                } catch (InstantiationException e) {
                    e.printStackTrace();
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            });
        }

        return classList;
    }

    /**
     * 根据spi机制初加载对应接口的bean的信息放入map
     *
     * @param clazz
     * @throws IOException
     * @throws ClassNotFoundException
     */
    public void loadExtension(Class clazz) throws IOException, ClassNotFoundException {
        if (clazz == null) {
            throw new IllegalArgumentException("class 没找到");
        }

        // 获取 ExtensionLoader 的类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        //存储接口的子类
        Map<String, Class> classMap = new HashMap<>();
        // 从系统SPI以及用户SPI中找bean
        for (String prefix : prefixs) {
            // SPI配置文件路径名
            String spiFilePath = prefix + clazz.getName();
            Enumeration<URL> enumeration = classLoader.getResources(spiFilePath);
            while (enumeration.hasMoreElements()) {
                URL url = enumeration.nextElement();
                InputStreamReader inputStreamReader = null;
                // 按字符读取字节流
                inputStreamReader = new InputStreamReader(url.openStream());
                BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
                String line;
                while ((line = bufferedReader.readLine()) != null && !line.equals("")) {
                    String[] lineArr = line.split("=");
                    String key = lineArr[0];
                    String value = lineArr[1];
                    final Class<?> aClass = Class.forName(value);
                    extensionClassCache.put(key, aClass);
                    classMap.put(key, aClass);
                    logger.info("加载bean key：{} , value：{}", key, value);
                }
            }
        }
        // 存储接口子类的bean集合
        extensionClassCaches.put(clazz.getName(),classMap);
    }
}
